package org.jeecg.modules.oms.parser.impl.optimization;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.oms.entity.*;
import org.jeecg.modules.oms.parser.OptimizationFileProcessor;
import org.jeecg.modules.oms.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 新格尔门类型优化单处理器
 * 专门处理门类型订单的优化单文件解析
 */
@Slf4j
@Component
public class XingeDoorOptimizationFileProcessor implements OptimizationFileProcessor {

    @Autowired
    private IProductSalesOrderService productSalesOrderService;

    @Autowired
    private IXingeProfileMaterialService xingeProfileMaterialService;

    @Autowired
    private IXingeProfileCutDetailService xingeProfileCutDetailService;

    @Autowired
    private IProductSalesOrderProgressService productSalesOrderProgressService;

    @Autowired
    private IDesignFileService designFileService;

    @Autowired
    private IProductSalesOrderDetailService detailService;
    @Autowired
    private IXgeProfileSizeTableService xgeProfileSizeTableService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean processOptimizationFile(String orderId, MultipartFile file, String userId, String userName, List<ProductSalesOrder> orderList) {
        log.info("开始处理门类型优化单文件，订单ID: {}", orderId);

        try {
            // 获取订单信息，修改为根据orderId获取订单列表并拼接orderNo
            String[] orderIdArray = orderId.split(",");
            ArrayList<String> orderNoList = new ArrayList<>();
            for (ProductSalesOrder order : orderList) {
                if (order == null) {
                    log.error("未找到订单, 订单ID: {}", orderId);
                    throw new JeecgBootException("未找到订单, 订单ID: " + orderId);
                } else {
                    orderNoList.add(order.getOrderNo());
                }
            }

            // 读取Excel文件
            Workbook workbook = getWorkbook(file);
            if (workbook == null) {
                throw new JeecgBootException("无法读取Excel文件，文件可能损坏或格式不正确");
            }

            // 解析型材清单和切割方案
            List<HashMap<String, Object>> profileMaterialsWithCuts = parseProfileMaterials(workbook, orderId, String.join(",", orderNoList));

            // 提取型材列表和切割方案列表
            List<XingeProfileMaterial> profileMaterials = new ArrayList<>();
            List<XingeProfileCutDetail> allCutDetails = new ArrayList<>();
            
            for (HashMap<String, Object> resultMap : profileMaterialsWithCuts) {
                XingeProfileMaterial material = (XingeProfileMaterial) resultMap.get("material");
                @SuppressWarnings("unchecked")
                List<XingeProfileCutDetail> cutDetails = (List<XingeProfileCutDetail>) resultMap.get("cutDetailList");
                
                if (material != null) {
                    profileMaterials.add(material);
                }
                if (cutDetails != null && !cutDetails.isEmpty()) {
                    allCutDetails.addAll(cutDetails);
                }
            }

            // 保存型材清单
            if (!profileMaterials.isEmpty()) {
                // 先删除旧数据
                xingeProfileMaterialService.deleteByOrderId(orderId);

                // 批量保存新数据
                boolean saved = xingeProfileMaterialService.saveBatch(profileMaterials);
                if (!saved) {
                    log.error("保存型材清单失败, 订单ID: {}", orderId);
                    throw new JeecgBootException("保存型材清单失败, 订单ID: " + orderId);
                }
                
                log.info("门类型优化单型材清单处理成功, 订单ID: {}, 型材数量: {}", orderId, profileMaterials.size());
                
                // 为切割方案设置正确的profileMaterialId
                for (int i = 0; i < profileMaterials.size() && i < profileMaterialsWithCuts.size(); i++) {
                    XingeProfileMaterial savedMaterial = profileMaterials.get(i);
                    @SuppressWarnings("unchecked")
                    List<XingeProfileCutDetail> cutDetails = (List<XingeProfileCutDetail>) profileMaterialsWithCuts.get(i).get("cutDetailList");
                    
                    if (cutDetails != null && savedMaterial.getId() != null) {
                        for (XingeProfileCutDetail cutDetail : cutDetails) {
                            cutDetail.setProfileMaterialId(savedMaterial.getId());
                        }
                    }
                }
            } else {
                log.error("未解析到型材清单数据, 订单ID: {}", orderId);
                throw new JeecgBootException("未解析到型材清单数据, 订单ID: " + orderId);
            }
            
            // 保存详细切割方案
            if (!allCutDetails.isEmpty()) {
                // 先删除旧数据
                xingeProfileCutDetailService.deleteByOrderId(orderId);
                
                //要根据orderDetailCode查询订单明细ID
                try {
                    allCutDetails.forEach(cutDetail -> {
                        if(cutDetail.getOrderDetailCode() != null){
                            ProductSalesOrderDetail orderDetail = detailService.getOne(new LambdaQueryWrapper<ProductSalesOrderDetail>()
                                    .eq(ProductSalesOrderDetail::getWindowNo, cutDetail.getOrderDetailCode()));
                            if (orderDetail == null) {
                                log.error("未找到对应的订单明细, 窗号: {}", cutDetail.getOrderDetailCode());
                                throw new JeecgBootException("未找到对应的订单明细, 窗号: " + cutDetail.getOrderDetailCode());
                            }
                            
                            XgeProfileSizeTable xgeProfileSizeTable = new XgeProfileSizeTable();
                            xgeProfileSizeTable.setDetailId(orderDetail.getId());
                            xgeProfileSizeTable.setWindowNo(orderDetail.getWindowNo());
                            xgeProfileSizeTable.setProfileCode(cutDetail.getProfileCode());
                            xgeProfileSizeTable.setProfileName(cutDetail.getProfileName());
                            xgeProfileSizeTable.setColor(cutDetail.getColor());
                            xgeProfileSizeTable.setCutAngle(cutDetail.getCutDirection());
                            xgeProfileSizeTable.setLength(cutDetail.getLength());
                            xgeProfileSizeTable.setQuantity(cutDetail.getQuantity());
                            
                            boolean sizeTableSaved = xgeProfileSizeTableService.save(xgeProfileSizeTable);
                            if (!sizeTableSaved) {
                                throw new JeecgBootException("保存型材尺寸表失败, 窗号: " + cutDetail.getOrderDetailCode());
                            }
                        }
                    });
                } catch (Exception e) {
                    log.error("保存型材尺寸表失败, 订单ID: {}", orderId, e);
                    throw new JeecgBootException("保存型材尺寸表失败: " + e.getMessage());
                }

                // 批量保存新数据
                boolean saved = xingeProfileCutDetailService.saveBatch(allCutDetails);
                if (!saved) {
                    log.error("保存详细切割方案失败, 订单ID: {}", orderId);
                    throw new JeecgBootException("保存详细切割方案失败, 订单ID: " + orderId);
                }

                log.info("门类型优化单详细切割方案处理成功, 订单ID: {}, 切割方案数量: {}", orderId, allCutDetails.size());
            } else {
                log.error("未解析到详细切割方案数据, 订单ID: {}", orderId);
                throw new JeecgBootException("未解析到详细切割方案数据, 订单ID: " + orderId);
            }

            // 调用designFileService保存优化单文件
            try {
                boolean fileSuccess = designFileService.uploadOptimizationFile(orderId, file, userId, userName);
                if (!fileSuccess) {
                    log.error("保存优化单文件记录失败, 订单ID: {}", orderId);
                    throw new JeecgBootException("保存优化单文件记录失败, 订单ID: " + orderId);
                }
            } catch (Exception e) {
                log.error("保存优化单文件记录异常, 订单ID: {}", orderId, e);
                throw new JeecgBootException("保存优化单文件记录异常: " + e.getMessage());
            }

            // 更新订单状态为"已上传优化单-待提交审核"(状态码3)
            for (String id : orderIdArray) {
                ProductSalesOrder order = productSalesOrderService.getById(id);
                Integer oldStatus = order.getStatus();
                if (oldStatus != null) { // 确保当前状态为"已上传汇总单-待上传优化单"
                    order.setStatus(3); // 更新为"已上传优化单-待提交审核"
                    productSalesOrderService.updateById(order);

                    // 记录订单进度
                    try {
                        // 创建订单进度记录
                        ProductSalesOrderProgress progress = new ProductSalesOrderProgress();
                        progress.setOrderId(orderId);
                        progress.setOldStatus(oldStatus);
                        progress.setNewStatus(3);
                        progress.setChangeTime(new Date());
                        progress.setOperatorId(userId);
                        progress.setOperatorName(userName);
                        progress.setChangeReason("上传优化单");
                        productSalesOrderProgressService.save(progress);
                    } catch (Exception e) {
                        // 进度记录失败不影响主流程
                        log.error("记录订单进度失败", e);
                    }
                }
            }

            log.info("门类型优化单文件处理完成, 订单ID: {}", orderId);
            return true;

        } catch (JeecgBootException e) {
            log.error("处理门类型优化单文件业务异常, 订单ID: {}, 错误: {}", orderId, e.getMessage());
            throw e; // 重新抛出业务异常，确保事务回滚
        } catch (Exception e) {
            log.error("处理门类型优化单文件时发生系统错误, 订单ID: {}", orderId, e);
            throw new JeecgBootException("处理门类型优化单文件时发生系统错误: " + e.getMessage());
        }
    }

    /**
     * 获取Workbook对象，根据文件后缀返回不同的Workbook实例
     */
    private Workbook getWorkbook(MultipartFile file) {
        try {
            String fileName = file.getOriginalFilename();
            if (fileName == null) {
                log.error("文件名为空");
                return null;
            }

            InputStream inputStream = file.getInputStream();

            // 根据文件后缀选择不同的Workbook实现
            if (fileName.toLowerCase().endsWith(".xlsx")) {
                return new XSSFWorkbook(inputStream);
            } else if (fileName.toLowerCase().endsWith(".xls")) {
                return new HSSFWorkbook(inputStream);
            } else {
                log.error("不支持的文件格式: {}", fileName);
                return null;
            }
        } catch (IOException e) {
            log.error("读取Excel文件失败", e);
            return null;
        }
    }

    /**
     * 解析型材清单 - 门类型优化单专用
     * 此处的orderId可能是多个订单的id  为了处理合单情况，这里传入的orderId是一个字符串，多个订单用逗号分隔
     */
    private List<HashMap<String, Object>> parseProfileMaterials(Workbook workbook, String orderId, String orderNo) {
        Sheet sheet = workbook.getSheetAt(0);
        List<HashMap<String, Object>> sheetMaterials = parseDoorSheetProfileMaterials(sheet, orderId, orderNo);
        return sheetMaterials;
    }

    /**
     * 解析单个Sheet中的门类型型材清单
     */
    private List<HashMap<String, Object>> parseDoorSheetProfileMaterials(Sheet sheet, String orderId, String orderNo) {
        List<HashMap<String, Object>> materials = new ArrayList<>();

        // 先遍历获取所有型材区域范围
        List<MaterialRegion> materialRegions = findMaterialRegions(sheet);
        if (materialRegions.isEmpty()) {
            log.info("在Sheet[{}]中未找到型材区域", sheet.getSheetName());
            return materials;
        }

        log.info("找到 {} 个型材区域", materialRegions.size());

        // 遍历每个型材区域，解析详细信息
        for (MaterialRegion region : materialRegions) {
            HashMap<String, Object> resultMap = parseMaterialFromRegion(sheet, region, orderId, orderNo);
            if (resultMap != null) {
                materials.add(resultMap);
            }
        }

        return materials;
    }

    /**
     * 查找所有型材区域范围
     * 0列包含"原材料名称"为开始行，0列为空白为结束行
     */
    private List<MaterialRegion> findMaterialRegions(Sheet sheet) {
        List<MaterialRegion> regions = new ArrayList<>();

        // 遍历所有行查找包含"原材料名称"的行作为区域开始
        for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
            Row row = sheet.getRow(rowNum);
            if (row == null) continue;

            Cell firstCell = row.getCell(0);
            if (firstCell != null && firstCell.getCellType() == CellType.STRING) {
                String cellValue = firstCell.getStringCellValue().trim();

                // 判断是否是型材区域的开始行（0列包含"原材料名称"）
                if (cellValue.contains("原材料名称")) {
                    // 找到该区域的结束行（向下直至0列为空白行）
                    int endRow = findMaterialRegionEndRow(sheet, rowNum);
                    if (endRow > rowNum) {
                        regions.add(new MaterialRegion(rowNum, endRow, cellValue));
                        log.info("找到型材区域: 开始行={}, 结束行={}, 原材料名称={}", rowNum, endRow, cellValue);
                    }
                }
            }
        }

        return regions;
    }

    /**
     * 查找型材区域的结束行（从开始行向下直至0列为空白行）
     */
    private int findMaterialRegionEndRow(Sheet sheet, int startRow) {
        for (int rowNum = startRow + 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
            Row row = sheet.getRow(rowNum);

            // 如果遇到空行，则认为是区域结束
            if (row == null) {
                return rowNum - 1;
            }

            Cell firstCell = row.getCell(0);
            // 如果0列为空白，则认为是区域结束
            if (firstCell == null ||
                    firstCell.getCellType() == CellType.BLANK ||
                    StringUtils.isBlank(firstCell.getStringCellValue().trim())) {
                return rowNum - 1;
            }

            // 如果遇到下一个"原材料名称"行，则认为是区域结束
            if (firstCell.getCellType() == CellType.STRING) {
                String cellValue = firstCell.getStringCellValue().trim();
                if (cellValue.contains("原材料名称")) {
                    return rowNum - 1;
                }
            }
        }

        return sheet.getLastRowNum();
    }

    /**
     * 从型材区域中解析型材信息
     */
    private HashMap<String, Object> parseMaterialFromRegion(Sheet sheet, MaterialRegion region, String orderId, String orderNo) {
        try {
            // 获取原材料名称行的信息
            Row materialNameRow = sheet.getRow(region.getStartRow());
            if (materialNameRow == null) return null;

            String materialNameLine = region.getMaterialNameLine();
            log.info("解析型材区域: 开始行={}, 结束行={}, 原材料信息={}",
                    region.getStartRow(), region.getEndRow(), materialNameLine);

            // 从原材料名称行解析基本信息  原材料名称 编码 颜色 长度 规格 系列 余料上限（取上） 余料下限（取下）
            String profileCode = "";
            String profileName = "";
            String color = "";
            String length = "";
            String specification = "";
            String series = "";
            String upperLimit = "";
            String lowerLimit = "";

            // 解析多行格式的原材料信息
            String[] lines = materialNameLine.split("\\r?\\n");
            for (String line : lines) {
                line = line.trim();
                if (StringUtils.isBlank(line)) continue;

                // 解析原材料名称
                if (line.contains("原材料名称：") || line.contains("原材料名称:")) {
                    profileName = extractValue(line, "原材料名称[：:]");
                }
                // 解析编码
                else if (line.contains("编码：") || line.contains("编码:")) {
                    profileCode = extractValue(line, "编码[：:]");
                }
                // 解析颜色
                else if (line.contains("颜色：") || line.contains("颜色:")) {
                    color = extractValue(line, "颜色[：:]");
                }
                // 解析长度
                else if (line.contains("长度：") || line.contains("长度:")) {
                    length = extractValue(line, "长度[：:]");
                }
                // 解析规格
                else if (line.contains("规格：") || line.contains("规格:")) {
                    specification = extractValue(line, "规格[：:]");
                }
                // 解析系列
                else if (line.contains("系列：") || line.contains("系列:")) {
                    series = extractValue(line, "系列[：:]");
                }
                // 解析余料上限
                else if (line.contains("余料上限") && (line.contains("取上") || line.contains("："))) {
                    upperLimit = extractValue(line, "余料上限\\(取上\\)[：:]");
                }
                // 解析余料下限
                else if (line.contains("余料下限") && (line.contains("取下") || line.contains("："))) {
                    lowerLimit = extractValue(line, "余料下限\\(取下\\)[：:]");
                }
            }

            log.info("解析结果: 名称={}, 编码={}, 颜色={}, 长度={}, 规格={}, 系列={}, 上限={}, 下限={}",
                    profileName, profileCode, color, length, specification, series, upperLimit, lowerLimit);

            // 创建型材对象
            XingeProfileMaterial material = new XingeProfileMaterial();
            material.setOrderId(orderId);
            material.setOrderNo(orderNo);
            if (StringUtils.isNotBlank(profileCode)) {
                material.setProfileCode(profileCode);
            }
            if (StringUtils.isNotBlank(profileName)) {
                material.setProfileName(profileName);
            }
            if (StringUtils.isNotBlank(color)) {
                material.setColor(color);
            }
            if (StringUtils.isNotBlank(length)) {
                try {
                    material.setLength(Double.valueOf(length));
                } catch (NumberFormatException e) {
                    log.error("长度格式转换失败: {}", length);
                    throw new JeecgBootException("长度格式转换失败: " + length);
                }
            }
            material.setCreateTime(new Date());
            //从开始行的第二行获取数量信息
            Row materialQuantityRow = sheet.getRow(region.getStartRow() + 1);
            if (materialQuantityRow != null) {
                String materialQuantityLine = getCellValueAsString(materialQuantityRow.getCell(0));
                String[] quantityLines = materialQuantityLine.split("\\r?\\n");
                for (String line : quantityLines) {
                    line = line.trim();
                    if (StringUtils.isBlank(line)) continue;
                    // 解析数量
                    if (line.contains("数量：") || line.contains("数量:")) {
                        String quantityValue = extractValue(line, "数量[：:]");
                        if (StringUtils.isNotBlank(quantityValue)) {
                            try {
                                material.setQuantity(Integer.parseInt(quantityValue));
                            } catch (NumberFormatException e) {
                                log.error("数量格式转换失败: {}", quantityValue);
                                throw new JeecgBootException("数量格式转换失败: " + quantityValue);
                            }
                        }
                        break;
                    }
                }
            }
            
            // 如果没有解析到数量，设置默认值
            if (material.getQuantity() == null) {
                material.setQuantity(1);
            }
            //遍历获取详细切割方案表头列索引
            Row headerRow = sheet.getRow(region.startRow + 2);
            HashMap<String, Integer> columnMap = new HashMap<>();
            for (int i = 0; i <= headerRow.getLastCellNum(); i++) {
                //切割方案 锯向 数量 优化率 余料 关联订单明细编号
                Cell cell = headerRow.getCell(i);
                if (cell == null) continue;
                String cellValueAsString = cell.getStringCellValue();
                if (StringUtils.isNotBlank(cellValueAsString) && cellValueAsString.equals("切割方案")) {
                    columnMap.put(cellValueAsString, i);
                } else if (StringUtils.isNotBlank(cellValueAsString) && cellValueAsString.equals("锯向")) {
                    columnMap.put(cellValueAsString, i);
                } else if(StringUtils.isNotBlank(cellValueAsString) && cellValueAsString.equals("数量")) {
                    columnMap.put(cellValueAsString, i);
                } else if(StringUtils.isNotBlank(cellValueAsString) && cellValueAsString.equals("优化率")) {
                    columnMap.put(cellValueAsString, i);
                } else if(StringUtils.isNotBlank(cellValueAsString) && cellValueAsString.equals("余料")) {
                    columnMap.put(cellValueAsString, i);
                } else if(StringUtils.isNotBlank(cellValueAsString) && cellValueAsString.equals("订单号")) {
                    columnMap.put(cellValueAsString, i);
                }
            }
            List<XingeProfileCutDetail> cutDetails = new ArrayList<>();

            //遍历行获取详细切割方案  从开始行+3开始
            for (int i = region.startRow + 3; i <= region.endRow; i++) {
                Row row = sheet.getRow(i);
                if (row == null) continue;
                
                try {
                    // 安全获取单元格值
                    String cutScheme = getCellValueAsString(row.getCell(columnMap.get("切割方案")));
                    String cutDirection = getCellValueAsString(row.getCell(columnMap.get("锯向")));
                    String quantity = getCellValueAsString(row.getCell(columnMap.get("数量")));
                    String optimizationRate = getCellValueAsString(row.getCell(columnMap.get("优化率")));
                    String scrap = getCellValueAsString(row.getCell(columnMap.get("余料")));
                    String orderDetailId = getCellValueAsString(row.getCell(columnMap.get("订单号")));
                    
                    // 跳过空行
                    if (StringUtils.isBlank(cutScheme) && StringUtils.isBlank(quantity)) {
                        continue;
                    }
                    
                    XingeProfileCutDetail xingeProfileCutDetail = new XingeProfileCutDetail();
                    xingeProfileCutDetail.setOrderId(orderId);
                    xingeProfileCutDetail.setOrderNo(orderNo);
                    xingeProfileCutDetail.setProfileCode(profileCode);
                    xingeProfileCutDetail.setProfileName(profileName);
                    xingeProfileCutDetail.setColor(color);
                    xingeProfileCutDetail.setCutScheme(cutScheme);
                    xingeProfileCutDetail.setCutDirection(cutDirection);
                    xingeProfileCutDetail.setSerialNo(i - region.startRow - 2); // 相对序号
                    xingeProfileCutDetail.setCreateTime(new Date());
                    
                    // 安全转换数值类型
                    if (StringUtils.isNotBlank(length)) {
                        try {
                            xingeProfileCutDetail.setLength(Double.valueOf(length));
                        } catch (NumberFormatException e) {
                            log.error("长度格式转换失败: {}", length);
                            throw new JeecgBootException("长度格式转换失败: " + length);
                        }
                    }
                    
                    if (StringUtils.isNotBlank(quantity)) {
                        try {
                            xingeProfileCutDetail.setQuantity(Integer.valueOf(quantity));
                        } catch (NumberFormatException e) {
                            log.error("数量格式转换失败: {}", quantity);
                            throw new JeecgBootException("数量格式转换失败: " + quantity);
                        }
                    }
                    
                    if (StringUtils.isNotBlank(optimizationRate)) {
                        try {
                            //optimizationRate的值为 91.37%  只提取数字部分91.37 需要携带小数点
                            optimizationRate = optimizationRate.split("%")[0];

                            xingeProfileCutDetail.setOptimizationRate(Double.valueOf(optimizationRate) / 100);
                        } catch (NumberFormatException e) {
                            log.warn("优化率格式转换失败: {}", optimizationRate);
                            throw new RuntimeException("优化率格式转换失败: " + optimizationRate);
                        }
                    }
                    
                    if (StringUtils.isNotBlank(scrap)) {
                        try {
                            xingeProfileCutDetail.setRemnant(Double.valueOf(scrap));
                        } catch (NumberFormatException e) {
                            log.error("余料格式转换失败: {}", scrap);
                            throw new JeecgBootException("余料格式转换失败: " + scrap);
                        }
                    }
                    
                    // 注意：这里暂时将订单号存储在profileMaterialId中，后续会被正确的ID替换
                    if (StringUtils.isNotBlank(orderDetailId)) {
                        xingeProfileCutDetail.setOrderDetailCode(orderDetailId);
                    }
                    
                    cutDetails.add(xingeProfileCutDetail);
                    
                } catch (Exception e) {
                    log.error("解析切割方案行失败，行号: {}, 错误: {}", i, e.getMessage());
                    throw new JeecgBootException("解析切割方案行失败，行号: " + i + ", 错误: " + e.getMessage());
                }
            }
            HashMap<String, Object> resultMap = new HashMap<>();
            resultMap.put("material",material);
            resultMap.put("cutDetailList",cutDetails);

            return resultMap;

        } catch (Exception e) {
            log.error("解析型材区域失败: 开始行={}, 结束行={}", region.getStartRow(), region.getEndRow(), e);
            return null;
        }
    }


    /**
     * 从行中解析门类型切割明细数据
     */
    private List<XingeProfileCutDetail> parseDoorCutDetailsFromRow(Row row, String orderId, String orderNo, String materialName, String profileCode) {
        List<XingeProfileCutDetail> cutDetails = new ArrayList<>();

        try {
            // 解析切割方案（遍历所有列查找包含"*"的切割信息）
            for (int colIndex = 0; colIndex < row.getLastCellNum(); colIndex++) {
                String cutInfo = getCellValueAsString(row.getCell(colIndex));
                if (StringUtils.isNotBlank(cutInfo) && cutInfo.contains("*")) {
                    // 解析类似 "2013*2 698*2" 的切割信息
                    List<XingeProfileCutDetail> parsedDetails = parseDoorCutInfo(cutInfo, orderId, orderNo, materialName, profileCode);
                    cutDetails.addAll(parsedDetails);
                }
            }

        } catch (Exception e) {
            log.error("解析门切割明细失败，行号: {}", row.getRowNum(), e);
        }

        return cutDetails;
    }

    /**
     * 解析门类型切割信息
     */
    private List<XingeProfileCutDetail> parseDoorCutInfo(String cutInfo, String orderId, String orderNo, String materialName, String profileCode) {
        List<XingeProfileCutDetail> cutDetails = new ArrayList<>();

        try {
            // 使用正则表达式解析切割信息，如 "2013*2 698*2"
            Pattern pattern = Pattern.compile("(\\d+)\\*(\\d+)");
            Matcher matcher = pattern.matcher(cutInfo);

            while (matcher.find()) {
                XingeProfileCutDetail cutDetail = new XingeProfileCutDetail();
                cutDetail.setOrderId(orderId);
                cutDetail.setOrderNo(orderNo);
                cutDetail.setProfileName(materialName);
                cutDetail.setProfileCode(profileCode);
                cutDetail.setCreateTime(new Date());

                // 解析长度和数量
                Double length = Double.parseDouble(matcher.group(1));
                Integer quantity = Integer.parseInt(matcher.group(2));

                cutDetail.setLength(length);
                cutDetail.setQuantity(quantity);
                cutDetail.setCutScheme(matcher.group(1) + "*" + matcher.group(2));

                cutDetails.add(cutDetail);
            }

        } catch (Exception e) {
            log.error("解析门类型切割信息失败: {}", cutInfo, e);
        }

        return cutDetails;
    }

    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return DateUtils.formatDate(cell.getDateCellValue(), "yyyy-MM-dd");
                } else {
                    return String.valueOf((int) cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return String.valueOf(cell.getStringCellValue());
                } catch (Exception e) {
                    try {
                        return String.valueOf(cell.getNumericCellValue());
                    } catch (Exception ex) {
                        return "";
                    }
                }
            default:
                return "";
        }
    }


    /**
     * 从字符串中提取指定键的值
     *
     * @param line       待解析的行
     * @param keyPattern 键的正则表达式模式
     * @return 提取的值
     */
    private String extractValue(String line, String keyPattern) {
        try {
            // 构建完整的正则表达式：键名 + 冒号 + 值
            String pattern = keyPattern + "\\s*([^\\s]+)";
            java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern);
            java.util.regex.Matcher m = p.matcher(line);

            if (m.find()) {
                return m.group(1).trim();
            }

            // 如果正则匹配失败，尝试简单的字符串分割
            String[] parts = line.split("[：:]");
            if (parts.length >= 2) {
                return parts[1].trim();
            }

            return "";
        } catch (Exception e) {
            log.error("解析值失败: line={}, pattern={}", line, keyPattern, e);
            throw new JeecgBootException("解析值失败: line=" + line + ", pattern=" + keyPattern + ", 错误: " + e.getMessage());
        }
    }

    /**
     * 型材区域信息
     */
    private static class MaterialRegion {
        private final int startRow;
        private final int endRow;
        private final String materialNameLine;

        public MaterialRegion(int startRow, int endRow, String materialNameLine) {
            this.startRow = startRow;
            this.endRow = endRow;
            this.materialNameLine = materialNameLine;
        }

        public int getStartRow() {
            return startRow;
        }

        public int getEndRow() {
            return endRow;
        }

        public String getMaterialNameLine() {
            return materialNameLine;
        }
    }

}
